﻿namespace PlaylistCopy.ViewModels.Impl
{
    using CuttingEdge.Conditions;
    using PlaylistCopy.Common;
    using PlaylistCopy.Contract;
    using PlaylistCopy.Extensions;
    using PlaylistCopy.Helpers;
    using PlaylistCopy.Localization;
    using PlaylistCopy.Logging;
    using PlaylistCopy.Properties;
    using PlaylistCopy.Services;
    using PlaylistCopy.Services.Impl;
    using PropertyChanged;
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Windows.Input;

    [ImplementPropertyChanged]
    internal class MainWindowVm : IMainWindowVm
    {
        private readonly IDialogService dialogService;

        private readonly IPlaylistService playlistService;

        private readonly INotificationService notificationService;

        private readonly IWindowFactory windowFactory;

        private readonly ILogger logger;

        private readonly IFileService fileService;

        private readonly IDirectoryService directoryService;

        public MainWindowVm(IDialogService dialogService, IPlaylistService playlistService, ILogger logger,
                            INotificationService notificationService, IWindowFactory windowFactory,
                            IFileService fileService, IDirectoryService directoryService)
        {
            this.dialogService = dialogService;
            this.playlistService = playlistService;
            this.logger = logger;
            this.notificationService = notificationService;
            this.windowFactory = windowFactory;
            this.fileService = fileService;
            this.directoryService = directoryService;

            this.AvailableCopyModes = Enum.GetValues(typeof(CopyMode)).OfType<CopyMode>().ToArray();

            this.T = NullLocalizer.Instance;
        }

        public Localizer T { get; set; }

        public string PlaylistPath { get; set; }

        public string DestinationPath { get; set; }

        public IEnumerable<CopyMode> AvailableCopyModes
        {
            get;
            private set;
        }
        public CopyMode CopyMode { get; set; }
        public string RootPath { get; set; }

        public string ModeDescription
        {
            get
            {
                switch (this.CopyMode)
                {
                    case CopyMode.Direct:
                        return Resources.DirectDescription;
                    case CopyMode.PreserveStrcture:
                        return Resources.PreserveDescription;
                    case CopyMode.TryPreserveStructure:
                        return Resources.TryPreserveDescription;
                    default:
                        return Resources.NoDescription;
                }
            }
        }

        public bool CanStart
        {
            get
            {
                return !string.IsNullOrWhiteSpace(this.PlaylistPath) && !string.IsNullOrWhiteSpace(this.DestinationPath);
            }
        }

        public bool OverwriteFiles { get; set; }

        public ICommand OpenDestinationPathCommand
        {
            get
            {
                return new DelegateCommand(this.OpenDestinationFolder);
            }
        }

        public ICommand OpenPlaylistCommand
        {
            get
            {
                return new DelegateCommand(this.OpenPlaylist);
            }
        }

        public ICommand CopyPlaylistCommand
        {
            get
            {
                return new DelegateCommand(() =>
                                           {
                                               if (!this.CheckBeforeStart())
                                               {
                                                   return;
                                               }

                                               this.dialogService.ProgressDialog(this.CopyPlaylistWork);
                                           });
            }
        }

        public ICommand OpenPreserveRootPath
        {
            get
            {
                return new DelegateCommand(() =>
                                           {
                                               var path = this.dialogService.OpenFolder();
                                               if (!string.IsNullOrWhiteSpace(path))
                                               {
                                                   this.RootPath = path;
                                               }
                                           });
            }
        }

        public ICommand AboutCommand
        {
            get { return new DelegateCommand(() => this.windowFactory.CreateAboutWindow(this).ShowDialog()); }
        }

        private void CopyPlaylistWork(IWorkArguments workArguments)
        {
            var playlistImpl = this.playlistService.GetPlaylistForFilePath(this.PlaylistPath);
            var eventLogger = new BufferedLogger();

            var engine = new PlaylistCopyEngine(options =>
                                                {
                                                    options.WithPlaylist(playlistImpl)
                                                           .WithPlaylistFile(this.PlaylistPath)
                                                           .WithOutputDirectory(this.DestinationPath)
                                                           .WithCopyService(new FileService())
                                                           .WithWorkArguments(workArguments)
                                                           .WithLogger(eventLogger)
                                                           .WithDirectoryService(this.directoryService)
                                                           .WithLocalizer(this.T);

                                                    switch (this.CopyMode)
                                                    {
                                                        case CopyMode.Direct:
                                                            options.DirectCopy();
                                                            break;
                                                        case CopyMode.TryPreserveStructure:
                                                            options.TryPreserveStructure();
                                                            break;
                                                        case CopyMode.PreserveStrcture:
                                                            options.PreserveStructure(this.RootPath);
                                                            break;
                                                    }
                                                });

            var result = true;

            try
            {
                engine.Copy();
            }
            catch (Exception ex)
            {
                eventLogger.Error(this.T("UnexpectedError", ex.Message));
                this.logger.ErrorException(ex, "Error while copying files.");
                result = false;
            }

            DispatcherHelper.SafeDispatch(() =>
                                          {
                                              var summaryWindow = this.windowFactory.CreateSummaryWindow(this);

                                              summaryWindow.Logs(eventLogger);
                                              summaryWindow.Status(result 
                                                                    ? SummaryStatus.Success 
                                                                    : SummaryStatus.Error);
                                              summaryWindow.ShowDialog();
                                          });
        }

        private bool CheckBeforeStart()
        {
            if (this.fileService.Exists(this.PlaylistPath))
            {
                return true;
            }

            this.notificationService.Error(this.T("PlaylistFileDoesntExist"));
            return false;
        }

        private void OpenDestinationFolder()
        {
            var path = this.dialogService.OpenFolder();
            if (path != null)
            {
                this.DestinationPath = path;
            }
        }

        private void OpenPlaylist()
        {
            var extensions = this.playlistService.GetAllExtensions().SafeEvaluate();
            var file = this.dialogService.OpenSingleFile(null, extensions.ToDialogFilterExpression());

            if (string.IsNullOrWhiteSpace(file))
            {
                return;
            }

            if (!CheckExtensions(file, extensions))
            {
                this.notificationService.Error(this.T("FileTypeNotSupported"));
                return;
            }

            this.PlaylistPath = file;
        }

        private bool CheckExtensions(string file, IEnumerable<string> availableExtensions)
        {
            Condition.Requires(file, "file").IsNotNullOrWhiteSpace();
            // ReSharper disable once PossibleMultipleEnumeration
            Condition.Requires(availableExtensions, "availableExtensions").IsNotNull();
            // ReSharper disable once PossibleMultipleEnumeration

            var extensions = availableExtensions.SafeEvaluate();
            if (!extensions.Any())
            {
                return false;
            }

            var ext = this.fileService.FileExtension(file);
            return !extensions.Contains(ext);
        }
    }
}
